#ifndef __SINGLE_LIST_H__
#define __SINGLE_LIST_H__

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif


/**
 * user customer node type define like flow:
 * struct my_node
 * {
 *    single_list_node_t node; //the struct must stay first place of this struct my_node
 *    uint32_t value;
 * };
 */

/**define like this, is avoid more small memory alloc and then memory fragmentation */
typedef struct single_list_node_s
{
    struct single_list_node_s* next;
}single_list_node_t;


typedef struct single_list_s
{
    uint32_t node_count;
    void(*nodeFree)(void* node);
    /**
     * -1: node1 <  node2
     *  0: node1 == node2
     *  1: node1 >  node2
     */
    int (*compare)(single_list_node_t* node1, single_list_node_t* node2);    
    single_list_node_t* head;
    single_list_node_t* tail; /** for fast push back operation */
}single_list_t;


#define SListSetFreeMethod(l,m) ((l)->nodeFree = (m))
#define SListSetCompareMethod(l,m) ((l)->compare = (m))

#define SListNodeFree(l) ((l)->nodeFree)
#define SListNodeCompare(l) ((l)->compare)

#define SListFront(l) (((l) != NULL) ? (l)->head.next : NULL)
#define SListBack(l)  (((l) != NULL) ? (1)->tail : NULL)

single_list_t* SListCreate();
void SListDestroy(single_list_t* sl);

void SListClear(single_list_t* sl);

bool SListIsEmpty(single_list_t* sl);
uint32_t SListLength(single_list_t* sl);

single_list_t* SListPushBack(single_list_t* sl, single_list_node_t* node);
single_list_t* SListPushFront(single_list_t* sl, single_list_node_t* node);

void SListPopFront(single_list_t* sl);

/** @brief insert 'node' after 'pos'
 * success: true, else: false 
 *
 */
bool SListInsert(single_list_t* sl, single_list_node_t* pos, single_list_node_t* node);

/** @brief remove 'node' after 'pos'
 * success: true, else: false
 *
 */
bool SListRemove(single_list_t* sl, single_list_node_t* pos, single_list_node_t* node);

/** erase target node for single list, this will foreach list */
bool SListErase(single_list_t* sl, single_list_node_t* node);


single_list_node_t* SListFind(single_list_t* sl, single_list_node_t* target);

/**the index start from 0 */
single_list_node_t* SListAt(single_list_t* sl, uint32_t index);

single_list_t* SListRewind(single_list_t* sl);

/**true: have cycle, false: haven't 
 * slow and fast pointer
 */
bool SListCycleCheck(single_list_t* sl);

/**true: have cycle, false: haven't
 * use list counter,foreach list, if step count > list->length, then have cycle
 */
bool SListCycleFastCheck(single_list_t* sl);


/** from little to big ,
 *  note: sl1 and sl2 the node data type must the same.
 */
single_list_t* SListMerge(single_list_t* sl1, single_list_t* sl2);


/**Delete the penultimate nth node of the linked list, n is the index start from list tail */
bool SListDeleteBack(single_list_t* sl, uint32_t n);


single_list_node_t* SListGetMiddleNode(single_list_t* sl);


void SListForeach(single_list_t* sl, void(*opt)(single_list_node_t* node, uint32_t idx));

/** only support the value type of node is char, and must set 'compare' function */
bool SListCheckPalindrome(single_list_t* sl);


#ifdef __cplusplus
}
#endif // __cplusplus


#endif // !__SINGLE_LIST_H__

